﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ObserverModel3
{
    public struct TransData
    {
        int a, b, c;
        public TransData(int a, int b, int c)
        {
            this.a = a;
            this.b = b;
            this.c = c;
        }
        public int A
        {
            get
            {
                return a;
            }
            set
            {
                a = value;
            }
        }
        public int B
        {
            get
            {
                return b;
            }
            set
            {
                b = value;
            }
        }
        public int C
        {
            get
            {
                return c;
            }
            set
            {
                c = value;
            }
        }
    }

    public class WeatherData : IObservable<TransData>
    {
        List<IObserver<TransData>> observers;
        public WeatherData()
        {
            observers = new List<IObserver<TransData>>();
        }

        #region IObservable<TransData> Members
        public IDisposable Subscribe(IObserver<TransData> observer)
        {
            if (!observers.Contains(observer))
                observers.Add(observer);
            return new Unsubscriber(observers, observer);
        }
        #endregion

        private class Unsubscriber : IDisposable
        {
            private List<IObserver<TransData>> _observers;
            private IObserver<TransData> _observer;

            public Unsubscriber(List<IObserver<TransData>> observers, IObserver<TransData> observer)
            {
                this._observers = observers;
                this._observer = observer;
            }

            public void Dispose()
            {
                if (_observer != null && _observers.Contains(_observer))
                    _observers.Remove(_observer);
            }
        }

        public void TrackLocation(Nullable<TransData> loc)
        {
            foreach (var observer in observers)
            {
                if (!loc.HasValue)
                    observer.OnError(null);
                else
                    observer.OnNext(loc.Value);
            }
        }

        public void EndTransmission()
        {
            foreach (var observer in observers.ToArray())
                if (observers.Contains(observer))
                    observer.OnCompleted();

            observers.Clear();
        }
    }

    public class ShowBordA : IObserver<TransData>
    {

        private IDisposable unsubscriber;
        private string instName;

        public ShowBordA(string name)
        {
            this.instName = name;
        }

        public string Name
        { get { return this.instName; } }

        public virtual void Subscribe(IObservable<TransData> provider)
        {
            if (provider != null)
                unsubscriber = provider.Subscribe(this);
        }

        public virtual void OnCompleted()
        {
            Console.WriteLine("The Location Tracker has completed transmitting data to {0}.", this.Name);
            this.Unsubscribe();
        }

        public virtual void OnError(Exception e)
        {
            Console.WriteLine("{0}: The location cannot be determined.", this.Name);
        }

        public virtual void OnNext(TransData value)
        {
            Console.WriteLine("{2}: The current location is {0}, {1}", value.A, value.B, this.Name);
        }

        public virtual void Unsubscribe()
        {
            unsubscriber.Dispose();
        }
    }

    //public class ShowBordB : IObserver<WeatherData>
    //{
    //}
    //public class ShowBordC : IObserver<WeatherData>
    //{
    //}



    class Program
    {
        static void Main(string[] args)
        {
            WeatherData provider = new WeatherData();
            ShowBordA reporter1 = new ShowBordA("SHOW PANEL A");
            reporter1.Subscribe(provider);

            ShowBordA reporter2 = new ShowBordA("MobileGPS");
            reporter2.Subscribe(provider);

            provider.TrackLocation(new TransData(4, 8, 1));
            reporter1.Unsubscribe();

            provider.TrackLocation(new TransData(14, 18, 11));
            provider.TrackLocation(null);
            provider.EndTransmission();
            Console.ReadLine();
        }
    }
}
